﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.Configuration;
using System.Configuration;

/// <summary>
/// A page which guides the user through setup.
/// </summary>
public partial class Install : System.Web.UI.Page
{
    /// <summary>
    /// Attempts to fill text box values from the current settings on first load.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void Page_Load(object sender, EventArgs e)
    {
        if(WebConfigurationManager.AppSettings.AllKeys.Contains("salt") && WebConfigurationManager.AppSettings["salt"].Length > 0) {
            Response.Redirect("~/Default.aspx");
        }
        pnlError.Visible = false;
        if(!Page.IsPostBack) {
            radDBMode.DataSource = EnumBinder.EnumHelper.ToExtendedList<int>(typeof(Database.DatabaseType));
            radDBMode.DataTextField = "Value";
            radDBMode.DataValueField = "NumericKey";
            radDBMode.DataBind();

            if(WebConfigurationManager.AppSettings.Count > 0) {
                try {
                    radDBMode.SelectedValue = WebConfigurationManager.AppSettings["dbtype"];
                    txtDBHost.Text = WebConfigurationManager.AppSettings["dbhost"];
                    txtDBPort.Text = WebConfigurationManager.AppSettings["dbport"];
                    txtDBUser.Text = WebConfigurationManager.AppSettings["dbuser"];
                    txtDBPassword.Text = WebConfigurationManager.AppSettings["dbpass"];
                    txtDBDatabase.Text = WebConfigurationManager.AppSettings["dbdatabase"];
                    txtTablePrefix.Text = WebConfigurationManager.AppSettings["TablePrefix"];
                } catch { }
            } else {
                radDBMode.SelectedIndex = 0;
                txtDBPort.Text = "3306";
            }
            wzdInstall.ActiveStepIndex = 0;
            Master.Page.Form.DefaultButton = wzdInstall.FindControl("StartNavigationTemplateContainerID$StartNextButton").UniqueID;
        } else {
            switch(wzdInstall.ActiveStepIndex) { // set the default button to next
                case 0:
                    Master.Page.Form.DefaultButton = wzdInstall.FindControl("StepNavigationTemplateContainerID$StepNextButton").UniqueID;
                    break;
                case 1:
                    Master.Page.Form.DefaultButton = wzdInstall.FindControl("FinishNavigationTemplateContainerID$FinishButton").UniqueID;
                    break;
                default:
                    Master.Page.Form.DefaultButton = wzdInstall.FindControl("StepNavigationTemplateContainerID$StepNextButton").UniqueID;
                    break;
            }
        }
    }

    /// <summary>
    /// Saves the settings entered at each stage.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.Web.UI.WebControls.WizardNavigationEventArgs"/> instance containing the event data.</param>
    protected void wzdInstall_NextButtonClick(object sender, WizardNavigationEventArgs e) {
        try {
            Database db;
            Database.DatabaseType dbType;
            string connectionString,
                   tablePrefix = txtTablePrefix.Text;
            System.Configuration.ConnectionStringSettings conn = null;
            System.Configuration.Configuration config;
            KeyValueConfigurationCollection appSettings;
            switch(e.CurrentStepIndex) {
                case 0:
                    dbType = (Database.DatabaseType)Enum.Parse(typeof(Database.DatabaseType), radDBMode.SelectedValue);
                    connectionString = Database.GetConnectionString(dbType, txtDBHost.Text, int.Parse(txtDBPort.Text), txtDBUser.Text, txtDBPassword.Text, txtDBDatabase.Text);
                    db = new Database(dbType, connectionString, tablePrefix);
                    Session["pw"] = txtDBPassword.Text;
                    try {
                        //db = new Database();
                        db.CreateTables(true, true, true, true, true, true);
                    } catch(Exception tEx) {
                        lblError.Text = "Error creating tables - " + tEx.Message;
                        pnlError.Visible = true;
                    }
                    break;
                case 1:
                    config = WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
                    appSettings = config.AppSettings.Settings;
                    txtDBPassword.Text = Session["pw"].ToString();
                    dbType = (Database.DatabaseType)Enum.Parse(typeof(Database.DatabaseType), radDBMode.SelectedValue);
                    connectionString = Database.GetConnectionString(dbType, txtDBHost.Text, int.Parse(txtDBPort.Text), txtDBUser.Text, txtDBPassword.Text, txtDBDatabase.Text);
                    db = new Database(dbType, connectionString, tablePrefix);
                    switch(radDBMode.SelectedIndex) {
                        case 0:
                            conn = new ConnectionStringSettings("Default", connectionString, "MySql.Data.MySqlClient");
                            break;
                        case 1:
                            conn = new ConnectionStringSettings("Default", connectionString, "System.Data.SqlClient");
                            break;
                    }
                    appSettings.Clear();
                    appSettings.Add("dbtype", radDBMode.SelectedValue);
                    appSettings.Add("dbhost", txtDBHost.Text);
                    appSettings.Add("dbport", txtDBPort.Text);
                    appSettings.Add("dbuser", txtDBUser.Text);
                    appSettings.Add("dbpass", txtDBPassword.Text);
                    appSettings.Add("dbdatabase", txtDBDatabase.Text);
                    appSettings.Add("TablePrefix", tablePrefix);
                    config.ConnectionStrings.ConnectionStrings.Clear();
                    config.ConnectionStrings.ConnectionStrings.Add(conn);
                    using(Database.Command cmd = db.CreateCommand()) {
                        string salt = Utils.GenID(true);
                        db.OpenConnection();
                        cmd.CommandText = "DELETE FROM " + tablePrefix + "users WHERE username = @user";
                        cmd.AddParameterWithValue("@user", txtAdminUsername.Text);
                        cmd.ExecuteNonQuery();
                        cmd.CommandText = "INSERT INTO " + tablePrefix + "users (username, password, permissions) VALUES (@user, @password, @permissions)";
                        cmd.AddParameterWithValue("@password", Utils.SaltPassword(txtAdminPassword.Text, salt));
                        cmd.AddParameterWithValue("@permissions", ((int)Constants.Permissions.ChangeSettings).ToString());
                        cmd.ExecuteNonQuery();
                        if(appSettings.AllKeys.Contains("salt")) {
                            appSettings.Remove("salt");
                        }
                        appSettings.Add("salt", salt); // now save the salt to prevent access to the installer
                        config.Save();
                        config = WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
                        Session.Remove("connectionstring");
                    }
                    break;
            }
        } catch(System.Configuration.ConfigurationErrorsException cEx) {
            lblError.Text = "Error #401: Errorneous configuration - " + cEx.Message;
            pnlError.Visible = true;
            e.Cancel = true;
        } catch(System.UnauthorizedAccessException uEx) {
            lblError.Text = "Error #402: The ASP.NET account must have access to the directory - " + uEx.Message;
            pnlError.Visible = true;
            e.Cancel = true;
        } catch(InvalidOperationException iEx) {
            lblError.Text = "Error #403: " + iEx.Message;
            pnlError.Visible = true;
            e.Cancel = true;
        } catch(MySql.Data.MySqlClient.MySqlException mEx) {
            lblError.Text = "Error #404: Could not connect to MySQL - " + mEx.Message;
            pnlError.Visible = true;
            e.Cancel = true;
        } catch(Exception ex) {
            lblError.Text = "Could not connect to the database with the specified settings: " + ex.Message;
            pnlError.Visible = true;
            e.Cancel = true;
        }
    }

    /// <summary>
    /// Sets the default port when the SQL server type changes.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void radDBMode_SelectedIndexChanged(object sender, EventArgs e) {
        switch(radDBMode.SelectedValue) {
            case "0":
                txtDBPort.Text = "3306";
                break;
            case "1":
                txtDBPort.Text = "1433";
                break;
        }
    }
}
